/*
 * @Author: OreoWang
 * @Email: ihc523@163.com
 * @Date: 2022-04-25 16:48:39
 * @LastEditors: OreoWang
 * @LastEditTime: 2022-04-27 23:48:31
 * @Description: 
 */

import { Quat, Vec3 } from 'cc';
import { misc } from 'cc';
import { AnimationComponent } from 'cc';
import { SkeletalAnimation } from 'cc';
import { _decorator, Component, Node } from 'cc';
import bt from '../../script/behavior-runtime/main';
import { AIPlayer } from './AIPlayer';
const { ccclass, property } = _decorator;

let pos1 = new Vec3();
let pos2 = new Vec3();
let pos3 = new Vec3();
let out = new Vec3();

@ccclass('AIEnemy')
export class AIEnemy extends Component {
    @property(Node)
    target: Node = null;

    @property@property({
        type: AIPlayer,
        // visible: false,
    })
    aiPlayer: AIPlayer = null;

    @property(SkeletalAnimation)
    anim: SkeletalAnimation = null;
    
    @property({
        type: [Node],
    })
    patrolPoints: Node[] = [];

    private get player(){
        return this.aiPlayer?.node;
    }

    _index: number = 0;
    _animName: string = "";
    _animSpeed: number = 1;

    start () {
    }

    lerp(out: Vec3, a: Vec3, b: Vec3, t: number) {
        out.set(a);
        if(Vec3.distance(pos1, pos2) < 0.02){
        }
        else{
            let dir = b.subtract(a).normalize();
            dir = dir.multiplyScalar(t);
            out.add(dir);
        }
        return out;
    }

    onHasSight(){
        //当前位置
        pos1.set(this.target.position);
        //玩家位置
        pos2.set(this.player.position);

        //视野范围
        if(Vec3.distance(pos1, pos2) < 8){
            return bt.BehaviorStatus.Success;
        }

        return bt.BehaviorStatus.Failure;
    }

    onChase(){
        return bt.BehaviorStatus.Success;
    }

    onRandomMove(){
        this._playAnim("run", 1);
    
        //这里为了方便，只是按点索引顺序移动
        let point = this.patrolPoints[this._index];
        //自身点位置
        pos1.set(this.target.position);
        //目标点位置
        pos2.set(point.position);
        //朝向
        this.target.lookAt(pos2);
    
        //目标点达标与否阈值判断
        if(Vec3.distance(pos1, pos2) < 0.1){
            this._index++;
            if(this._index>=this.patrolPoints.length){
                this._index = 0;
            }
    
            this._playAnim("idle");
            //到达目标点时返回成功，由父节点 `Sequence` 顺序执行下一个子节点的行为，即 `原地休息`
            return bt.BehaviorStatus.Success;
        }
        else{
            let pos = this.lerp(out, pos1, pos2, 0.02);
            this.target.setPosition(pos);  
    
            //未到达目标点时返回 Running ，由父节点 `Sequence` 下一次 tick 继续执行
            return bt.BehaviorStatus.Running;  
        }
    }

    onMoveToAttack(){
        if(this.canAttack()==bt.BehaviorStatus.Success){
            return bt.BehaviorStatus.Failure;
        }
        else{
            pos1.set(this.target.position);
            pos2.set(this.player.position);
            this.target.lookAt(pos2);
            
            let pos = this.lerp(out, pos1, pos2, 0.03);
            this.target.setPosition(pos);

            this._playAnim("runHit");
            return bt.BehaviorStatus.Running;
        }
    }

    needMoveClose(){
        if(this.canAttack()==bt.BehaviorStatus.Success){
            return bt.BehaviorStatus.Failure;
        }

        return bt.BehaviorStatus.Success;
    }

    canAttack(){
        //当前位置
        pos1.set(this.target.position);
        //玩家位置
        pos2.set(this.player.position);

        //受击范围判断
        if(Vec3.distance(pos1, pos2) < 1){
            return bt.BehaviorStatus.Success;
        }

        return bt.BehaviorStatus.Failure;
    }

    onAttack(){
        this._playAnim("attackLeft");
        //一次攻击结束后等待技能冷却，所以在攻击动作结束后播放防御动画 'fightIdel'
        this.anim.once(AnimationComponent.EventType.LASTFRAME, ()=>{
            this._playAnim("fightIdle");
        })
        //主角受击
        this.aiPlayer.beAttacked();
        return bt.BehaviorStatus.Success;
    }

    onIdle(){
        this._playAnim("idle");

        return bt.BehaviorStatus.Running;
    }

    
    _playAnim(name: string, speed = 1){
        if(this._animName == name && this._animSpeed == speed){
            return;
        }

        if(this._animName!=name){
            this.anim.play(name);
        }
        let state = this.anim.getState(name);
        state.speed = speed;
        this.anim.onLoad
        
        this._animName = name;
        this._animSpeed = speed;
    }
}
